CibNav : Analyse exlporatoire des données

Author

Pierre Camilleri

Published

April 18, 2023

Préparation des données

Les données explorées sont celles de l’échantillon d’entraînement.

Code
df <- tbl(con, "dataset_train") %>%
  collect()
Code
df$cible <- as.logical(df$cible)
df$annee_visite <- as.integer(df$annee_visite)
df$id_gin_visite <- as.integer(df$id_gin_visite)
df$sitrep_history <- as.integer(df$sitrep_history)

df$log_jauge_oslo <- log10(df$jauge_oslo)
df$log_puissance_administrative <- log10(df$puissance_administrative)
df$log_longueur_hors_tout <- log10(df$longueur_hors_tout)
df$log_nombre_prescriptions <- log10(df$nombre_prescriptions)

Data preliminary exploration

Code
df_no_log <- df %>% select(!starts_with("log"))
plot_intro(df_no_log)

Code
plot_missing(df_no_log)

Valeurs manquantes essentiellement pour : 

  • le genre de navigation
  • la jauge oslo

Quelques valeurs manquantes pour :

  • les informations moteur (nbre, type, carburant)
  • la puissance admininistrative
Code
exclude <- c(
  "date_visite",
  "cible"
  )
plot_bar(df %>% select(!any_of(exclude)))

Histogrammes des variables catégorielles

Observations :

genre_navigation

  • Valeurs multiples agrégées : exemple “Conchyl.Petite Pêche”
  • Pourrait être regroupé en catégories plus générales, par ex : “Cabotage International” + “Cabotage national” < “Cabotage”

materiau_coque

  • Valeurs manquantes avec modalité “INCONNU”
  • Queue de modalités avec peu d’observations. À regrouper avec “AUTRES”

type_carburant

  • Présence de NA ET “INCONNU”
  • Queue de modalités avec peu d’observations. À regrouper avec “AUTRES”

type_moteur

  • Queue de modalités avec peu d’observations. À regrouper dans une catégorie “AUTRES”
Code
df <- df %>%
  mutate(
    genre_navigation = fct_lump_min(
      genre_navigation,
      min = 500,
      other_level = "Autre"
    ),

    materiau_coque = fct_recode(
      materiau_coque,
      METAL = "AG/4 - ALU",
      METAL = "ACIER",
      METAL = "ACIER / INOX",
      METAL = "ALLIAGE LEGER",
      BOIS = "BOIS MASSIF",
      BOIS = "BOIS MOULE",
      BOIS = "CONTREPLAQUE",
      PLASTIQUE = "POLYESTER EPOXY",
      PLASTIQUE = "POLYETHYLENE",
      PLASTIQUE = "PLASTIQUE SANDWICH",
      NULL = "INCONNU"
    ),

    type_carburant = fct_lump_min(
      type_carburant,
      min = 500,
      other_level = "Autre"
    ),

    type_moteur = fct_lump_min(
      type_moteur,
      min = 500,
      other_level = "Autre"
      ),
  )

Les catégories avec peu de modalités ont été regroupées dans une catégorie “Autre”.

Code
exclude <- c(
  "date_visite",
  "cible"
  )
plot_bar(df %>% select(!any_of(exclude)))

Histogrammes des variables catégorielles après regroupements de modalités

Code
plot_bar(df, by = "situation_flotteur")
1 columns ignored with more than 50 categories.
date_visite: 1922 categories

Vérification correspondance genre <> situation flotteur

À quelques rares exceptions près, la correspondance genre_navigation <> situation_flotteur est assez cohérente.

Code
plot_histogram(
  df %>% select(-jauge_oslo, -puissance_administrative),
  geom_histogram_args = list(bins = 100L)
)

Observations :

  • age : Distribitution bi-modale avec un mode ~ 15 ans et un pic ~30 ans. Des pics ponctuels s’ajoutent à cette distribution : peut-être des arrondis ?

  • annee_visite : uniforme sur 2016 2022 puis très peu d’obs en 2023.

  • delai_visites : un pic à 365 (un an) donc a priori en jours. DEs pics secondaires, a priori autour de 2 ans, 2 ans et demi et 3 ans. Des valeurs étranges (1, 2, 3…). Mélange de données théoriques ou arrondies, et de données peut-être réelles ?

  • id_gin_visite distribué uniformément (comme on pourrait s’y attendre pour un id).

  • id_nav_flotteur est-ce que c’est censé être un entier ? forte concentration à un endroit, distribution plus diffuse sur deux autres intervalles.

  • jauge_oslo - Valeurs extrêmes

    • TODO appliquer log
Code
plot_correlation(na.omit(df), maxcat = 5L)
3 features with more than 5 categories ignored!
date_visite: 1850 categories
genre_navigation: 16 categories
materiau_coque: 15 categories

Observations :

  • La cible est trés corrélé (sans surprise) avec le nombre de prescriptions.
  • Type moteur et type carburant assez redondant :
    • moteur éléctrique <> électricité
    • explosion <> essence (Plutôt les plus petits navires, moins de prescriptions)
    • combustion <> gazole
  • Situation_flotteur pêche (par rapport au commerce) :
    • plutôt les gros navires
  • Corrélation entre nombre prescriptions et annee visite ?
    • Forte corrélation entre presc majeurs et mineures
  • puissance administrative, longueur, jauge_oslo, et nb_moteurs très correlées
Code
ggplot(
  df %>% sample_n(10000),
  aes(x = nombre_prescriptions, y = nombre_prescriptions_majeurs),
) +
   geom_point(
     position = position_jitter(width = 0.3, height = 0.3),
     alpha = 0.1
   ) +
   geom_smooth(method = "gam") +
   xlim(0, 15) +
   ylim(0, 3)
`geom_smooth()` using formula 'y ~ s(x, bs = "cs")'
Warning: Removed 219 rows containing non-finite values (stat_smooth).
Warning: Removed 4260 rows containing missing values (geom_point).

En moyenne (et à la louche), on trouve une prescription majeure pour 10 presciptions mineures, relation (quasi)-linéaire.

Code
ggplot(df, aes(x =age)) +
  geom_bar()

Code
ggplot(df %>% filter(genre_navigation %in% c(
  "Petite pêche",
  "Conchyl.Pure",
  "Pêche côtière",
   "Pêche au large",
   "Plaisance NC",
   "Navigation côtière")),
       aes(x =genre_navigation, y=age)) +
  geom_violin()

La bi-modalité de l’âge est visible pour les navires de pêche (petite pêche, conchyl, pêche côtière).

Code
df_pp <- df %>%
  filter(
    genre_navigation %in% c("Petite pêche"),
    type_moteur %in% c("Explosion", "Combustion Interne")
  )

p1 <- ggplot(df_pp,
       aes(x = age, y = puissance_administrative, color = type_moteur)) +
                 geom_jitter(height = 10, width = 0.5, alpha = 0.3)

p2 <- ggplot(df_pp,
       aes(x = age, color = type_moteur)) +
                 geom_density()

bayesplot_grid(p1, p2)

La bi-modalité s’explique principalement par le type de moteur ! Surprenant de voir peu de moteurs à combustion interne récents : changement législatif ?

Code
ggplot(
   df %>% filter(is.finite(puissance_administrative)),
   aes(x = longueur_hors_tout, y = puissance_administrative, color =situation_flotteur)
   ) +
                geom_point() +
                geom_smooth(method="lm")
`geom_smooth()` using formula 'y ~ x'

Code
ggplot(
   df %>% filter(is.finite(log_puissance_administrative)),
   aes(x = log_longueur_hors_tout, y = log_puissance_administrative, color =situation_flotteur)
   ) +
                geom_point() +
                geom_smooth(aes(color = situation_flotteur), method="gam")
`geom_smooth()` using formula 'y ~ s(x, bs = "cs")'

Ici on remarque plein de choses intéressantes :

  • Pour les navires commerciaux, il y a deux dynamiques puissance <> longueur très différentes entre, bien visible pour les grandes longueurs.

  • Il y a un effet de seuil important à la limite règlementaire

  • Il y a également un certain nombre de valeurs extrêmes de puissance pour des valeurs de longueur ~5m (log_long ~0.8)

  • Enfin, il y a un cluster de valeurs atypiques pour de faibles valeurs de longueur.

  • Pour les navires de pêches, il semble y avoir plus d’homogénéité, avec une relation quasi linéaire (rappel : en log-log)

    Hypothèses :

    • Régimes différents avant et après le seuil
    • Peut-être que le genre de navigation donne des informations ?
Code
p <- ggplot(
   df %>% filter(is.finite(log_puissance_administrative)) %>% sample_n(10000),
   aes(x = log_longueur_hors_tout, y = log_puissance_administrative, color =genre_navigation),
   ) +
                geom_point(position = position_jitter(width= 0.02, height = 0.02), alpha = 0.3) +
                # geom_density_2d() +
                geom_smooth(aes(group = situation_flotteur), method="gam",
                            color = "red") +
       facet_grid(rows = vars(situation_flotteur))

p
`geom_smooth()` using formula 'y ~ s(x, bs = "cs")'

Code
ggplotly(p)
`geom_smooth()` using formula 'y ~ s(x, bs = "cs")'

Concernant les deux dynamiques :

− avec cette visu, on voit même 3 dynamiques - la dynamique du bas représente plutôt des navires de plaisance - La navigation côtière s’insère entre les deux - Les navires de remorquage et de pilotage ont les puissances supérieures. - Les navires de cabotage international sont partagés entre les deux

Concernant le cluster de petits navires : - Genre essentiellement inconnu, sauf 1 > Navigation côtière Hypothèse : petits hors board de navig côtière

Concernant les navires de pêche : - Conchyl semble moins puissants en moyenne que petite pêche - Infra seuil : petite pêche ; supra seuil : pêche côtière

Autres observations :

  • Étonnement, il semble y avoir deux dynamiques pour les navires de plaisance également de longueur hors tout infra seuil

    Hypothèse : deux types de motorisations différentes

Code
p <- ggplot(
   df %>%
 filter(is.finite(log_puissance_administrative)) %>%
 filter(type_moteur %in% c("Explosion", "Combustion Interne", "Diesel électrique")),
   aes(x = log_longueur_hors_tout, y = log_puissance_administrative, color =genre_navigation),
   ) +
                geom_point(position = position_jitter(width= 0.02, height = 0.02), alpha = 0.3) +
                # geom_density_2d() +
                geom_smooth(aes(group = situation_flotteur), method="gam",
                            color = "red") +
       facet_grid(rows = vars(situation_flotteur), cols= vars(type_moteur))

p
`geom_smooth()` using formula 'y ~ s(x, bs = "cs")'

Code
ggplotly(p)
`geom_smooth()` using formula 'y ~ s(x, bs = "cs")'
  • On observe :
    • Les puissances valeurs extrêmes sont des moteurs à explosion
    • La plupart (mais pas tous) les navires de plaisance faible puissance sont à Combustion Interne, et forte puissance à explosion
    • La conchiliculture utilise beaucoup des navires à explosion
    • Les moteurs à explosion sont étagées contrairement aux moteurs à combustion interne

TODO : - Les clusters de points indiques plusieurs observations pour les même navires. Est-ce que l’apprentissage fait gaffe de ne pas mettre les mêmes navires en train et test ?

  • Visuellement, les pentes de puissance(longueur) (en log-log) semblent dépendre de la motorisation
Code
p <- ggplot(
   df %>%
 filter(is.finite(log_puissance_administrative)) %>%
 filter(type_moteur %in% c("Explosion", "Combustion Interne")) %>%
 sample_n(10000),
   aes(x = log_longueur_hors_tout, y = log_puissance_administrative, color = log_jauge_oslo),
   ) +
                geom_point(position = position_jitter(width= 0.02, height = 0.02), alpha = 0.5) +
                # geom_density_2d() +
                geom_smooth(aes(group = situation_flotteur), method="gam",
                            color = "red") +
       facet_grid(rows = vars(situation_flotteur), cols= vars(type_moteur)) +
       scale_color_distiller(palette = "Spectral")

p
`geom_smooth()` using formula 'y ~ s(x, bs = "cs")'

Code
ggplotly(p)
`geom_smooth()` using formula 'y ~ s(x, bs = "cs")'

Quelques anomalies de gros navires commerce + combustion interne qui ont une jauge Oslo très faible.

  • Jauge Oslo moteurs à explosion < jauge oslo moteur à combustion interne à longueur égale
  • Phénomène intéressant sur commerce + combustion interne, où les navires les moins puissants semblent avoir une plus grande jauge oslo (probablement loisir).
Code
p <- ggplot(
   df %>%
 filter(is.finite(log_puissance_administrative)) %>%
 sample_n(10000),
   aes(x = log_longueur_hors_tout, y = log_puissance_administrative, color =
       as.factor(materiau_coque))
   ) +
                geom_point(position = position_jitter(width= 0.02, height =
                                                      0.02), alpha = 0.5)

p

Code
ggplotly(p)
Code
p <- ggplot(
   df %>%
 filter(is.finite(log_puissance_administrative)) %>%
 filter(genre_navigation %in% c(
   "Petite pêche",
   "Conchyl.Pure",
   "Pêche côtière",
   "Pêche au large",
   "Plaisance NC",
   "Navigation côtière"
 )) %>%
 sample_n(10000),
   aes(x = log_longueur_hors_tout, y = log_puissance_administrative, color =
       as.factor(materiau_coque))
   ) +
                geom_point(position = position_jitter(width= 0.02, height = 0.02), alpha = 0.5) +
       facet_wrap(vars(genre_navigation))

p

Code
ggplotly(p)
  • Concernant les deux dynamiques de bateaux de plaisance, les faibles puissances ont la majorité des coques en bois, alors que les plus puissants ont des coques plastique ou alu

  • Un certain nombre de coques bois également pour la ptite pêche (même si plastique majoritaire).

  • Pour la conchyliculture, coques métal essentiellement

  • Les coques métal semblent préféré par les gros navires

Exploration du nombre de prescriptions majeures

Code
ggplot(
       df,
       aes(
         x = cut(age, 10),
         y = nombre_prescriptions_majeurs
       )) +
  stat_summary(fun = "mean", geom = "col")

Variations non monotones des prescriptions majeures avec l’âge

Code
# By length
ggplot(
       df,
       aes(
         x = cut(log_longueur_hors_tout, 10),
         y = nombre_prescriptions_majeurs
       )) +
  stat_summary(fun = "mean", geom = "col")

Variations quasi linéaire des prescr maj avec le log de la log_longueur_hors_tout

Code
ggplot(
       df %>% filter(genre_navigation %in% c(
  "Petite pêche",
  "Conchyl.Pure",
  "Pêche côtière",
   "Pêche au large",
   "Plaisance NC",
   "Navigation côtière",
   "Pilotage",
   "Lamanage")),
       aes(
         x = genre_navigation,
         y = nombre_prescriptions_majeurs
       )) +
  stat_summary(fun = "mean", geom = "col")

Les activités de pêche semblent avoir plus de prescr. majeures. Les activités de plaisance en ont le moins.

Code
ggplot(
       df,
       aes(
         x = type_moteur,
         y = nombre_prescriptions_majeurs
       )) +
  stat_summary(fun = "mean", geom = "col")

Nettement plus de prescr majeures pour les moteurs à comb interne que pour les moteurs électriques (ils sont aussi plus vieux)

Tentative de classification manuelle

Deux dynamiques de plaisance.

Code
df_class <- df
df_class$cat <- NA
Code
mod <- lm(
  log_puissance_administrative ~ log_longueur_hors_tout,
  data = df %>% filter(genre_navigation == "Plaisance NC")
)

df_class <- df_class %>%
  mutate(
    cat = ifelse(
      genre_navigation == "Plaisance NC" & log_puissance_administrative < predict(mod, df_class),
      "Plaisance",
      cat
    ),
    cat = ifelse(
      genre_navigation == "Plaisance NC" & log_puissance_administrative >= predict(mod, df_class),
      "Plaisance sport",
      cat
    )
    )
Code
p <- ggplot(
  df_class %>%
    sample_n(10000),
  aes(y  = log(nombre_prescriptions+1), x = cat, color = cat)) +
          geom_violin(adjust = 2, draw_quantiles = c(0.25, 0.5, 0.75)) +
          geom_jitter(height = 0.1, width = 0.5, alpha = 0.3)
  xlim(-1, 20)
<ScaleContinuousPosition>
 Range:  
 Limits:   -1 --   20
Code
  p

–> Difficulté d’analyser des graphiques avec des nombres de prescriptions, car beaucoup de variabilité sur des navires de même type.